﻿using System;
using System.Collections.Generic;
using System.Linq;
using DesignByContract.Exceptions;
using MadMediaManager.WPFSupport.Interfaces.ViewModels;
using MadMediaManager.WPFSupport.Services;
using MadMediaManager.WPFSupport.Services.Threading;
using Moq;
using NUnit.Framework;
using SharpTestsEx;
using TestHelper;

namespace MadMediaManager.WPFSupport.Tests
{
    [TestFixture]
    public class EventPublisherTest
    {
        [Test]
        public void Subscribe_NullAction_ThrowsException()
        {
            var eventPublisher = new EventPublisher(new DispatcherWrapper());

            Assert.Throws<PreconditionException>(() => eventPublisher.Subscribe<object>(null));
        }

        [Test]
        public void Subscribe_TargetDoesNotImplementISubscriber_ThrowsException()
        {
            var eventPublisher = new EventPublisher(new DispatcherWrapper());
            var nonSubscriber = new NonSubscriber();

            Assert.Throws<PreconditionException>(() => eventPublisher.Subscribe<object>(o => nonSubscriber.DoSomething()));
        }

        [Test]
        public void CanSubscribeAndPublish()
        {
            var eventPublisher = new EventPublisher(new DispatcherWrapper());
            var subscriber = new Subscriber();
            eventPublisher.Subscribe<object>(subscriber.DoSomething);

            var eventArgs = new object();
            eventPublisher.Publish(eventArgs);

            subscriber.DoSomethingExecuted.Should().Be.True();
            subscriber.PublishedObejct.Should().Be.SameInstanceAs(eventArgs);
        }

        [Test]
        public void CanUnSubscribe()
        {
            var eventPublisher = new EventPublisher(new DispatcherWrapper());
            var subscriber = new Mock<Subscriber>();
            eventPublisher.Subscribe<object>(subscriber.Object.DoSomething);
            eventPublisher.FieldValueEx<Dictionary<Type, List<Action<object>>>>("Subscribers")[typeof(object)].Should().Not.Be.Empty();

            subscriber.Raise(a => a.UnsubscribeOnDispose += null);
            eventPublisher.FieldValueEx<Dictionary<Type, List<Action<object>>>>("Subscribers")[typeof(object)].Should().Be.Empty();
        }
    }

    public class Subscriber : ISubscriber
    {
        public virtual event Action UnsubscribeOnDispose;

        public virtual bool DoSomethingExecuted { get; set; }
        public virtual object PublishedObejct { get; set; }

        public virtual void DoSomething(object o)
        {
            DoSomethingExecuted = true;
            PublishedObejct = o;
        }
    }

    public class NonSubscriber
    {
        public bool DoSomethingExecuted { get; set; }
        public void DoSomething()
        {
            DoSomethingExecuted = true;
        }
    }

}
